/* USER CODE BEGIN Header */
/**
  ******************************************************************************
  * @file           : main.c
  * @brief          : Main program body
  ******************************************************************************
  * @attention
  *
  * <h2><center>&copy; Copyright (c) 2019 STMicroelectronics.
  * All rights reserved.</center></h2>
  *
  * This software component is licensed by ST under BSD 3-Clause license,
  * the "License"; You may not use this file except in compliance with the
  * License. You may obtain a copy of the License at:
  *                        opensource.org/licenses/BSD-3-Clause
  *
  ******************************************************************************
  */
/* USER CODE END Header */

/* Includes ------------------------------------------------------------------*/
#include "main.h"
#include "adc.h"
#include "dma.h"
#include "i2c.h"
#include "tim.h"
#include "gpio.h"

/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */

#include "motor.h"
#include "measurement.h"
#include "bbb.h"
#include "utility.h"
#include "stm32f0xx_it.h"
#include "ssd1306.h"
#include "display.h"


/* USER CODE END Includes */

/* Private typedef -----------------------------------------------------------*/
/* USER CODE BEGIN PTD */

/* USER CODE END PTD */

/* Private define ------------------------------------------------------------*/
/* USER CODE BEGIN PD */
/* USER CODE END PD */

/* Private macro -------------------------------------------------------------*/
/* USER CODE BEGIN PM */

#define BEEPDUR	50
#define CONFIGWINDOWDURATION_MS	2000

/* USER CODE END PM */

/* Private variables ---------------------------------------------------------*/

/* USER CODE BEGIN PV */

bbb_BtnTd *PushBtn;
bbb_BtnTd *PullBtn;
bbb_BtnTd *CfgBtn;

static uint16_t SpeedModeList[] = {100, 250, 500, 750, 999};
static char* SpeedModeDesc[] = {"Min", "Low", "Med", "Hi ", "Max"};
static int8_t SpeedMode = 2;

static uint16_t RetractDurationList[] = {0, 500, 1000, 1500, 2000};
static char* RetractDurationDesc[] = {"Dis ", "0.5 s", "1.0 s", "1.5 s", "2.0 s"};
static int8_t RetractDuration = 2;

static disp_CfgModeTd CfgMode = disp_CfgModeTd_None;

static uint8_t RedrawRequested = 1;


/* USER CODE END PV */

/* Private function prototypes -----------------------------------------------*/
void SystemClock_Config(void);
/* USER CODE BEGIN PFP */

/* USER CODE END PFP */

/* Private user code ---------------------------------------------------------*/
/* USER CODE BEGIN 0 */

uint8_t StopWaitingDueToPushBtnRelease(void){
	uint8_t PushBtnState;
	bbb_GetBtnStates(&PushBtnState, 0, 0);

	return !PushBtnState;
}


uint8_t StopWaitingDueToPullBtnRelease(void){
	uint8_t PullBtnState;
	bbb_GetBtnStates(0, &PullBtnState, 0);

	return !PullBtnState;
}


uint8_t StopWaitingDueToAnyBtnPressed(void){
	uint8_t PushBtnState, PullBtnState, CfgBtnState;
	bbb_GetBtnStates(&PushBtnState, &PullBtnState, &CfgBtnState);
	return ( PushBtnState || PullBtnState || CfgBtnState);
}

/* USER CODE END 0 */

/**
  * @brief  The application entry point.
  * @retval int
  */
int main(void)
{
  /* USER CODE BEGIN 1 */
	uint32_t ConfigWindowTimestamp = 0;

	for(volatile uint32_t i=0; i<100000; i++);								//This delay helps probably with oscillator startup issue when it starts with 25% of supposed frequency for some reason (not investigated yet)

  /* USER CODE END 1 */
  

  /* MCU Configuration--------------------------------------------------------*/

  /* Reset of all peripherals, Initializes the Flash interface and the Systick. */
  

  LL_APB1_GRP2_EnableClock(LL_APB1_GRP2_PERIPH_SYSCFG);
  LL_APB1_GRP1_EnableClock(LL_APB1_GRP1_PERIPH_PWR);

  /* System interrupt init*/

  /* USER CODE BEGIN Init */

  /* USER CODE END Init */

  /* Configure the system clock */
  SystemClock_Config();

  /* USER CODE BEGIN SysInit */

  /* USER CODE END SysInit */

  /* Initialize all configured peripherals */
  MX_GPIO_Init();
  MX_DMA_Init();
  MX_ADC_Init();
  MX_TIM1_Init();
  MX_TIM3_Init();
  MX_TIM14_Init();
  MX_I2C1_Init();
  MX_TIM16_Init();
  MX_TIM17_Init();
  /* USER CODE BEGIN 2 */

  LL_DBGMCU_APB1_GRP2_FreezePeriph(LL_DBGMCU_APB1_GRP2_TIM1_STOP);
  LL_DBGMCU_APB1_GRP1_FreezePeriph(LL_DBGMCU_APB1_GRP2_TIM16_STOP|LL_DBGMCU_APB1_GRP2_TIM17_STOP);//__HAL_DBGMCU_FREEZE_TIM1();
  LL_SYSTICK_EnableIT();


  meas_Init();
  mo_Init();
  bbb_Init();
  ssd1306_Init();

  disp_DrawInitScreen();
  bbb_Melody3(bbb_ToneTd_Low, bbb_ToneTd_Med, bbb_ToneTd_High, 2*BEEPDUR);
  bbb_WaitSync(900);

  /* USER CODE END 2 */

  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
  while (1)
  {
	  if(RedrawRequested){
		  disp_DrawScreen(CfgMode, SpeedModeDesc[SpeedMode], RetractDurationDesc[RetractDuration], 0, 0, 0);
		  RedrawRequested = 0;
	  }

	  if(bbb_Update()){																	//Check whether any button has been pressed or released

		  PushBtn = bbb_GetPushBtnState();
		  PullBtn = bbb_GetPullBtnState();
		  CfgBtn = bbb_GetCfgBtnState();


		  if(CfgMode == disp_CfgModeTd_None){											//NORMAL PUSH/PULL OPERATION
			  if(PushBtn->PrevBtnEvt == bbb_EvtTd_Pressed){
				  mo_SetSpeed(0);														//Stop
				  bbb_WaitSync(10);														//Wait a moment to stop the movements
				  mo_SetSpeed(999);														//Start push with max speed to null the retraction effect
				  //bbb_WaitSync(RetractDurationList[RetractDuration]);					//Wait for retraction duration
				  bbb_WaitSyncCond(RetractDurationList[RetractDuration], StopWaitingDueToPushBtnRelease);
				  mo_SetSpeed(SpeedModeList[SpeedMode]);								//Set speed according to settings
				  bbb_WaitSyncCond(UINT16_MAX, StopWaitingDueToPushBtnRelease);			//Just synchronously wait so the code does not do anything
			  }
			  else if(PushBtn->PrevBtnEvt == bbb_EvtTd_Released || PushBtn->PrevBtnEvt == bbb_EvtTd_LongReleased){
				  mo_SetSpeed(0);														//Stop
				  bbb_WaitSync(10);														//Wait a moment to stop the movements
				  mo_SetSpeed(-999);													//Retract
				  //bbb_WaitSync(RetractDurationList[RetractDuration]);					//Still retract
				  bbb_WaitSyncCond(RetractDurationList[RetractDuration], StopWaitingDueToAnyBtnPressed);
				  mo_SetSpeed(0);
			  }

			  if(PullBtn->PrevBtnEvt == bbb_EvtTd_Pressed){								//When pull button is pressed start motor in reverse max speed
				  mo_SetSpeed(-999);
				  bbb_WaitSyncCond(UINT16_MAX, StopWaitingDueToPullBtnRelease);
			  }
			  else if(PullBtn->PrevBtnEvt == bbb_EvtTd_Released || PullBtn->PrevBtnEvt == bbb_EvtTd_LongReleased){						//When the button is released
				  mo_SetSpeed(0);
			  }
		  }
		  else{																			//CONFIGURATION MODE
			  if(PushBtn->PrevBtnEvt == bbb_EvtTd_Released){
				  if(CfgMode == disp_CfgModeTd_Ret){
					  RetractDuration++;
				  }
				  else if(CfgMode == disp_CfgModeTd_Speed){
					  SpeedMode++;
				  }
				  ConfigWindowTimestamp = GetTick() + CONFIGWINDOWDURATION_MS;
				  RedrawRequested = 1;
				  mo_SetSpeed(0);														//Stop
			  }

			  if(PullBtn->PrevBtnEvt == bbb_EvtTd_Released){							//When the button is released
				  if(CfgMode == disp_CfgModeTd_Ret){
					  RetractDuration--;
				  }
				  else if(CfgMode == disp_CfgModeTd_Speed){
					  SpeedMode--;
				  }
				  ConfigWindowTimestamp = GetTick() + CONFIGWINDOWDURATION_MS;
				  RedrawRequested = 1;
				  mo_SetSpeed(0);														//Stop
			  }

			  UT_SATURATE(RetractDuration, 0, (int8_t)(UT_SIZEOFARRAY(RetractDurationList)-1));
			  UT_SATURATE(SpeedMode, 0, (int8_t)(UT_SIZEOFARRAY(SpeedModeList)-1));
		  }


		  if(CfgBtn->PrevBtnEvt == bbb_EvtTd_Released){									//Config button always stops all movements and changes cfg mode

			  CfgMode += 1;
			  if(CfgMode > disp_CfgModeTd_Ret) CfgMode = disp_CfgModeTd_None;
			  mo_SetSpeed(0);													//Stop
			  ConfigWindowTimestamp = GetTick() + CONFIGWINDOWDURATION_MS;
			  RedrawRequested = 1;
			  mo_SetSpeed(0);														//Stop
		  }
	  }


	  if(ConfigWindowTimestamp && GetTick() > ConfigWindowTimestamp){
		  ConfigWindowTimestamp = 0;
		  CfgMode = disp_CfgModeTd_None;
		  RedrawRequested = 1;
	  }


    /* USER CODE END WHILE */

    /* USER CODE BEGIN 3 */
  }
  /* USER CODE END 3 */
}

/**
  * @brief System Clock Configuration
  * @retval None
  */
void SystemClock_Config(void)
{
  LL_FLASH_SetLatency(LL_FLASH_LATENCY_1);

  if(LL_FLASH_GetLatency() != LL_FLASH_LATENCY_1)
  {
  Error_Handler();  
  }
  LL_RCC_HSE_Enable();

   /* Wait till HSE is ready */
  while(LL_RCC_HSE_IsReady() != 1)
  {
    
  }
  LL_RCC_HSI14_Enable();

   /* Wait till HSI14 is ready */
  while(LL_RCC_HSI14_IsReady() != 1)
  {
    
  }
  LL_RCC_HSI14_SetCalibTrimming(16);
  LL_RCC_PLL_ConfigDomain_SYS(LL_RCC_PLLSOURCE_HSE_DIV_1, LL_RCC_PLL_MUL_6);
  LL_RCC_PLL_Enable();

   /* Wait till PLL is ready */
  while(LL_RCC_PLL_IsReady() != 1)
  {
    
  }
  LL_RCC_SetAHBPrescaler(LL_RCC_SYSCLK_DIV_1);
  LL_RCC_SetAPB1Prescaler(LL_RCC_APB1_DIV_1);
  LL_RCC_SetSysClkSource(LL_RCC_SYS_CLKSOURCE_PLL);

   /* Wait till System clock is ready */
  while(LL_RCC_GetSysClkSource() != LL_RCC_SYS_CLKSOURCE_STATUS_PLL)
  {
  
  }
  LL_Init1msTick(48000000);
  LL_SYSTICK_SetClkSource(LL_SYSTICK_CLKSOURCE_HCLK);
  LL_SetSystemCoreClock(48000000);
  LL_RCC_HSI14_EnableADCControl();
  LL_RCC_SetI2CClockSource(LL_RCC_I2C1_CLKSOURCE_SYSCLK);
}

/* USER CODE BEGIN 4 */

/* USER CODE END 4 */

/**
  * @brief  This function is executed in case of error occurrence.
  * @retval None
  */
void Error_Handler(void)
{
  /* USER CODE BEGIN Error_Handler_Debug */
  /* User can add his own implementation to report the HAL error return state */

  /* USER CODE END Error_Handler_Debug */
}

#ifdef  USE_FULL_ASSERT
/**
  * @brief  Reports the name of the source file and the source line number
  *         where the assert_param error has occurred.
  * @param  file: pointer to the source file name
  * @param  line: assert_param error line source number
  * @retval None
  */
void assert_failed(char *file, uint32_t line)
{ 
  /* USER CODE BEGIN 6 */
  /* User can add his own implementation to report the file name and line number,
     tex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) */
  /* USER CODE END 6 */
}
#endif /* USE_FULL_ASSERT */

/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
